package com.stox.core.ui.swing.widget;

import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.ComboBoxModel;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JComboBox;
import javax.swing.JTextField;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;


@SuppressWarnings("rawtypes")
public class FilteredComboBox extends JComboBox{
	private static final long serialVersionUID = -3429148386444077403L;
	protected Object[] array;
	protected JTextField textField;
	private OnSelectionCallback onSelectionCallback;
	
	public interface OnSelectionCallback{
		public void onSelection(Object selectedItem);
	}
	
	public FilteredComboBox(){
		this.setEditable(true);
		setModel(new DefaultComboBoxModel());
		textField = (JTextField) this.getEditor().getEditorComponent();
		FilteredComboEditorDocument lFilteredComboEditorDocument =
			new FilteredComboEditorDocument(this);
		textField.setDocument(lFilteredComboEditorDocument);
		textField.addKeyListener(lFilteredComboEditorDocument);
		textField.addFocusListener(lFilteredComboEditorDocument);
	}
	
	@SuppressWarnings("unchecked")
	@Override
	public void setModel(ComboBoxModel model) {
		array = new Object[model.getSize()];
		for(int i = 0; i < model.getSize(); i++){
			array[i] = model.getElementAt(i);
		}
		super.setModel(model);
	}
	
	public String isBeginOfItem(String text)
	{
		if(array == null){
			return null;
		}
		for (int i = 0; i < array.length; i++){
			if (array[i].toString().trim().toLowerCase().startsWith(text.trim().toLowerCase())){
				setSelectedIndex(i);
				return array[i].toString().substring(0, text.length());
			}
		}
		return null;
	}
 
	private class FilteredComboEditorDocument extends PlainDocument
																			implements KeyListener, FocusListener{
		private static final long serialVersionUID = 2593488305195781482L;
		
		protected FilteredComboBox parent;
		protected boolean operationInProgress;

		public FilteredComboEditorDocument(FilteredComboBox parentComboBox)
		{
			parent = parentComboBox;
			operationInProgress = false;
		}

		@Override
		public void insertString(int offset, String text, AttributeSet attributeSet)
			throws BadLocationException
		{
			if (!operationInProgress)
			{
				operationInProgress = true;
				String writtenText = getText(0, offset) + text;
				if (offset <= (getLength() - 1))
				{
					writtenText += getText(offset, getLength() - offset);
				}
				if (!parent.isPopupVisible()  &&  parent.isShowing())
				{
					showPopup();
				}

				String textToWrite = parent.isBeginOfItem(writtenText);
				if (textToWrite != null)
				{
					super.remove(0, getLength());
					super.insertString(0, textToWrite, attributeSet);
					textField.setCaretPosition(offset + text.length());
				}
				operationInProgress = false;
			}
		}
 
		@Override
		public void remove(int offset, int length)
			throws BadLocationException
		{
			if (!operationInProgress)
			{
				operationInProgress = true;
				if (offset == 0 && length == getLength())
				{
					super.remove(offset, length);
					operationInProgress = false;
				}
				else
				{
					String writtenText = getText(0, offset);
					if ((offset + length) <= (getLength() - 1))
					{
						writtenText
							+= getText(
								offset + length,
								getLength() - (offset + length));
					}
					String textToWrite =
						parent.isBeginOfItem(writtenText.trim());
					if (textToWrite != null)
					{
						if (!isPopupVisible())
						{
							showPopup();
						}
						super.remove(offset, length);
					}
					operationInProgress = false;
				}
			}
		}
  
		@Override
		public void keyPressed(KeyEvent event)
		{
			if (event.getKeyCode() == KeyEvent.VK_ENTER && isPopupVisible()){
				ensureAStringIsSelected();
				if(onSelectionCallback != null){
					onSelectionCallback.onSelection(getSelectedItem());
				}
			}
		}
		
		
 
		private void ensureAStringIsSelected()
		{
			try
			{
				remove(0, getLength());
				if (getSelectedIndex() == -1){
					Object obj = getItemAt(0);
					if(obj != null){
						super.insertString(0, getItemAt(0).toString(), null);
					}
				}else{
					super.insertString(0,  getSelectedItem().toString(), null);
				}
			}catch (BadLocationException e){
				e.printStackTrace();
			}
		}
		
		public void focusLost(FocusEvent sEvent){
			ensureAStringIsSelected();
		}
 
		public void keyReleased(KeyEvent sEvent){}
		public void focusGained(FocusEvent sEvent){	}
		public void keyTyped(KeyEvent sEvent){}
 	}

	public OnSelectionCallback getOnSelectionCallback() {
		return onSelectionCallback;
	}

	public void setOnSelectionCallback(final OnSelectionCallback onSelectionCallback) {
		this.onSelectionCallback = onSelectionCallback;
	}
}